package com.xyz.service.impl;

import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.xyz.dto.CountDto;
import com.xyz.dto.HomeLocalDateDto;
import com.xyz.entity.mapper.*;
import com.xyz.entity.pojo.*;
import com.xyz.service.CommonService;
import com.xyz.service.HomeAllService;
import com.xyz.util.dto.DataResult;
import com.xyz.util.dto.LoginInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

@Service
@Transactional(rollbackFor = Exception.class)
public class HomeAllServiceImpl implements HomeAllService {

    @Autowired
    private EquipmentInfoMapper equipmentInfoMapper;

    @Autowired
    private EquipmentTreeMapper equipmentTreeMapper;

    @Autowired
    private RepairWorkOrderMapper repairWorkOrderMapper;

    @Autowired
    private UpkeepWorkOrderMapper upkeepWorkOrderMapper;

    @Autowired
    private PatrolWorkOrderMapper patrolWorkOrderMapper;

    @Autowired
    private PartInfoMapper partInfoMapper;

    @Autowired
    private PartApplyMapper partApplyMapper;

    @Autowired
    private CommonService commonService;

    @Override
    public DataResult selectHead(LoginInfo loginInfo, CountDto countDto) throws Exception {
        HomeLocalDateDto dateDto = commonService.selectCountTime(countDto);
        Date date = new Date();

        // =====================
        EquipmentInfoExample eiExample = new EquipmentInfoExample();
        EquipmentInfoExample.Criteria eiCriteria = eiExample.createCriteria();
        eiCriteria.andIsDeleteEqualTo(0);
        eiCriteria.andIsScrapEqualTo(0);
        long emCount = equipmentInfoMapper.countByExample(eiExample);
        eiCriteria.andIsSpecialEqualTo(1);
        long emSpecialCount = equipmentInfoMapper.countByExample(eiExample);

        eiExample.clear();
        eiCriteria = eiExample.createCriteria();
        eiCriteria.andIsDeleteEqualTo(0);
        eiCriteria.andIsScrapEqualTo(0);
        eiCriteria.andEmStateNotEqualTo(3);
        long emImproperCount = equipmentInfoMapper.countByExample(eiExample);

        Map<String, Object> emMap = new HashMap<>();
        emMap.put("emCount", emCount);
        emMap.put("emSpecialCount", emSpecialCount);
        emMap.put("emImproperCount", emImproperCount);
        // =====================
        RepairWorkOrderExample rwoExample = new RepairWorkOrderExample();
        RepairWorkOrderExample.Criteria rwoCriteria = rwoExample.createCriteria();
        rwoCriteria.andCreateTimeGreaterThanOrEqualTo(DateUtil.beginOfDay(date));
        long repairTodayCount = repairWorkOrderMapper.countByExample(rwoExample);

        rwoExample.clear();
        rwoCriteria = rwoExample.createCriteria();
        rwoCriteria.andCreateTimeBetween(dateDto.getStartTime(), dateDto.getEndTime());
        long repairCount = repairWorkOrderMapper.countByExample(rwoExample);

        rwoExample.clear();
        rwoCriteria = rwoExample.createCriteria();
        rwoCriteria.andCreateTimeBetween(dateDto.getStartTime(), dateDto.getEndTime());
        rwoCriteria.andRepStateBetween(6, 10);
        long repairDisposeCount = repairWorkOrderMapper.countByExample(rwoExample);

        rwoExample.clear();
        rwoCriteria = rwoExample.createCriteria();
        rwoCriteria.andCreateTimeBetween(dateDto.getStartTime(), dateDto.getEndTime());
        rwoCriteria.andRepStateEqualTo(11);
        long repairCompleteCount = repairWorkOrderMapper.countByExample(rwoExample);

        Map<String, Object> repairMap = new HashMap<>();
        repairMap.put("repairCount", repairCount);
        repairMap.put("repairTodayCount", repairTodayCount);
        repairMap.put("repairDisposeCount", repairDisposeCount);
        repairMap.put("repairCompleteCount", repairCompleteCount);
        // =====================
        UpkeepWorkOrderExample uwoExample = new UpkeepWorkOrderExample();
        UpkeepWorkOrderExample.Criteria uwoCriteria = uwoExample.createCriteria();
        uwoCriteria.andCreateTimeGreaterThanOrEqualTo(DateUtil.beginOfDay(date));
        long upkeepTodayCount = upkeepWorkOrderMapper.countByExample(uwoExample);

        uwoExample.clear();
        uwoCriteria = uwoExample.createCriteria();
        uwoCriteria.andCreateTimeBetween(dateDto.getStartTime(), dateDto.getEndTime());
        long upkeepCount = upkeepWorkOrderMapper.countByExample(uwoExample);

        uwoExample.clear();
        uwoCriteria = uwoExample.createCriteria();
        uwoCriteria.andCreateTimeBetween(dateDto.getStartTime(), dateDto.getEndTime());
        uwoCriteria.andUpkeepStateBetween(6, 10);
        long upkeepDisposeCount = upkeepWorkOrderMapper.countByExample(uwoExample);

        uwoExample.clear();
        uwoCriteria = uwoExample.createCriteria();
        uwoCriteria.andCreateTimeBetween(dateDto.getStartTime(), dateDto.getEndTime());
        uwoCriteria.andUpkeepStateEqualTo(11);
        long upkeepCompleteCount = upkeepWorkOrderMapper.countByExample(uwoExample);

        Map<String, Object> upkeepMap = new HashMap<>();
        upkeepMap.put("upkeepCount", upkeepCount);
        upkeepMap.put("upkeepTodayCount", upkeepTodayCount);
        upkeepMap.put("upkeepDisposeCount", upkeepDisposeCount);
        upkeepMap.put("upkeepCompleteCount", upkeepCompleteCount);
        // =====================
        PatrolWorkOrderExample pwoExample = new PatrolWorkOrderExample();
        PatrolWorkOrderExample.Criteria pwoCriteria = pwoExample.createCriteria();
        pwoCriteria.andCreateTimeGreaterThanOrEqualTo(DateUtil.beginOfDay(date));
        long patrolTodayCount = patrolWorkOrderMapper.countByExample(pwoExample);

        pwoExample.clear();
        pwoCriteria = pwoExample.createCriteria();
        pwoCriteria.andCreateTimeBetween(dateDto.getStartTime(), dateDto.getEndTime());
        long patrolCount = patrolWorkOrderMapper.countByExample(pwoExample);

        pwoExample.clear();
        pwoCriteria = pwoExample.createCriteria();
        pwoCriteria.andCreateTimeBetween(dateDto.getStartTime(), dateDto.getEndTime());
        pwoCriteria.andStateIn(Arrays.asList(2, 3, 4, 6));
        long patrolDisposeCount = patrolWorkOrderMapper.countByExample(pwoExample);

        pwoExample.clear();
        pwoCriteria = pwoExample.createCriteria();
        pwoCriteria.andCreateTimeBetween(dateDto.getStartTime(), dateDto.getEndTime());
        pwoCriteria.andStateEqualTo(5);
        long patrolCompleteCount = patrolWorkOrderMapper.countByExample(pwoExample);

        Map<String, Object> patrolMap = new HashMap<>();
        patrolMap.put("patrolCount", patrolCount);
        patrolMap.put("patrolTodayCount", patrolTodayCount);
        patrolMap.put("patrolDisposeCount", patrolDisposeCount);
        patrolMap.put("patrolCompleteCount", patrolCompleteCount);
        // =====================
        PartInfoExample piExample = new PartInfoExample();
        PartInfoExample.Criteria piCriteria = piExample.createCriteria();
        piCriteria.andIsDeleteEqualTo(0);
        List<PartInfo> piList = partInfoMapper.selectByExample(piExample);
        int partNotStockCount = 0;
        for (PartInfo pi : piList) {
            if (pi.getWarnStock() <= pi.getStock()) {
                partNotStockCount++;
            }
        }

        PartApplyExample paExample = new PartApplyExample();
        PartApplyExample.Criteria paCriteria = paExample.createCriteria();
        paCriteria.andApplyTimeGreaterThanOrEqualTo(DateUtil.beginOfDay(date));
        long partTodayCount = partApplyMapper.countByExample(paExample);

        Map<String, Object> partMap = new HashMap<>();
        partMap.put("partCount", piList.size());
        partMap.put("partTodayCount", partTodayCount);
        partMap.put("partNotStockCount", partNotStockCount);
        // =====================
        Map<String, Object> map = new HashMap<>();
        map.put("em", emMap);
        map.put("repair", repairMap);
        map.put("upkeep", upkeepMap);
        map.put("patrol", patrolMap);
        map.put("part", partMap);
        return DataResult.build9100(map);
    }

    @Override
    public DataResult selectRepair(LoginInfo loginInfo, CountDto countDto) throws Exception {
        HomeLocalDateDto dateDto = commonService.selectCountTime(countDto);

        RepairWorkOrderExample rwoExample = new RepairWorkOrderExample();
        RepairWorkOrderExample.Criteria rwoCriteria = rwoExample.createCriteria();
        rwoCriteria.andCreateTimeBetween(dateDto.getStartTime(), dateDto.getEndTime());
        List<RepairWorkOrder> rwoList = repairWorkOrderMapper.selectByExample(rwoExample);

        Map<String, List<Integer>> rwoMap = new HashMap<>();
        for (RepairWorkOrder rwo : rwoList) {
            String key = DateUtil.formatDate(rwo.getCreateTime());
            List<Integer> rwoMapList;
            if (rwoMap.containsKey(key)) {
                rwoMapList = rwoMap.get(key);
            } else {
                rwoMapList = CollUtil.newArrayList(0, 0, 0);
            }
            if (rwo.getSourceType() == null) {
                rwoMapList.set(0, rwoMapList.get(0) + 1);
            } else if (rwo.getSourceType() == 1) {
                rwoMapList.set(1, rwoMapList.get(1) + 1);
            } else if (rwo.getSourceType() == 2) {
                rwoMapList.set(2, rwoMapList.get(2) + 1);
            }
            rwoMap.put(key, rwoMapList);
        }

        List<DateTime> dateList = DateUtil.rangeToList(dateDto.getStartTime(), dateDto.getEndTime(), DateField.DAY_OF_YEAR);

        List<String> chartNameList = new ArrayList<>();
        Map<String, Object> repairMap = new HashMap<>();
        Map<String, Object> upkeepMap = new HashMap<>();
        Map<String, Object> patrolMap = new HashMap<>();

        List<Integer> repairDataList = new ArrayList<>();
        List<Integer> upkeepDataList = new ArrayList<>();
        List<Integer> patrolDataList = new ArrayList<>();
        for (DateTime day : dateList) {
            chartNameList.add(DateUtil.format(day, "MM-dd"));
            String key = DateUtil.formatDate(day);
            if (rwoMap.containsKey(key)) {
                List<Integer> rwoMapList = rwoMap.get(key);
                repairDataList.add(rwoMapList.get(0));
                upkeepDataList.add(rwoMapList.get(1));
                patrolDataList.add(rwoMapList.get(2));
            } else {
                repairDataList.add(0);
                upkeepDataList.add(0);
                patrolDataList.add(0);
            }
        }

        List<Map<String, Object>> chartRowsList = new ArrayList<>();
        repairMap.put("name", "自主维修");
        repairMap.put("type", "line");
        repairMap.put("data", repairDataList);
        chartRowsList.add(repairMap);

        upkeepMap.put("name", "维保转维修");
        upkeepMap.put("type", "line");
        upkeepMap.put("data", upkeepDataList);
        chartRowsList.add(upkeepMap);

        patrolMap.put("name", "巡检转维修");
        patrolMap.put("type", "line");
        patrolMap.put("data", patrolDataList);
        chartRowsList.add(patrolMap);

        Map<String, Object> map = new HashMap<>();
        map.put("chartName", chartNameList);
        map.put("chartRows", chartRowsList);
        return DataResult.build9100(map);
    }

    @Override
    public DataResult selectEmRepair(LoginInfo loginInfo, CountDto countDto) throws Exception {
        HomeLocalDateDto dateDto = commonService.selectCountTime(countDto);
        int pageSize = Integer.parseInt(countDto.getPageSize());

        List<EquipmentTree> etList = equipmentTreeMapper.selectByExample(null);
        Map<Long, EquipmentTree> etMap = CollStreamUtil.toIdentityMap(etList, EquipmentTree::getId);

        RepairWorkOrderExample rwoExample = new RepairWorkOrderExample();
        RepairWorkOrderExample.Criteria rwoCriteria = rwoExample.createCriteria();
        rwoCriteria.andEmIdNotEqualTo(0L);
        rwoCriteria.andCreateTimeBetween(dateDto.getStartTime(), dateDto.getEndTime());
        List<RepairWorkOrder> rwoList = repairWorkOrderMapper.selectByExample(rwoExample);
        Map<Long, Integer> countMap = new HashMap<>();
        for (RepairWorkOrder rwo : rwoList) {
            long emId = rwo.getEmId();
            int count = countMap.containsKey(emId) ? countMap.get(emId) + 1 : 1;
            countMap.put(emId, count);
        }
        Comparator<Map.Entry<Long, Integer>> valueComparator = (o1, o2) -> o2.getValue() - o1.getValue();
        List<Map.Entry<Long, Integer>> countList = new ArrayList<>(countMap.entrySet());
        countList.sort(valueComparator);

        Map<Long, Integer> sortMap = new LinkedHashMap<>();
        for (Map.Entry<Long, Integer> entry : countList) {
            sortMap.put(entry.getKey(), entry.getValue());
            if (sortMap.size() >= pageSize) {
                break;
            }
        }

        if (sortMap.size() < pageSize) {
            EquipmentInfoExample eiExample = new EquipmentInfoExample();
            EquipmentInfoExample.Criteria eiCriteria = eiExample.createCriteria();
            if (sortMap.size() != 0) {
                eiCriteria.andIdNotIn(CollUtil.newArrayList(sortMap.keySet()));
            }
            eiCriteria.andIsScrapEqualTo(0);
            eiCriteria.andIsDeleteEqualTo(0);
            eiExample.setOrderByClause("id limit " + (pageSize - sortMap.size()));
            List<EquipmentInfo> eiList = equipmentInfoMapper.selectByExample(eiExample);
            for (EquipmentInfo ei : eiList) {
                sortMap.put(ei.getId(), 0);
            }
        }

        EquipmentInfoExample eiExample = new EquipmentInfoExample();
        EquipmentInfoExample.Criteria eiCriteria = eiExample.createCriteria();
        eiCriteria.andIdIn(CollUtil.newArrayList(sortMap.keySet()));
        List<EquipmentInfo> eiList = equipmentInfoMapper.selectByExample(eiExample);
        Map<Long, EquipmentInfo> eiMap = CollStreamUtil.toIdentityMap(eiList, EquipmentInfo::getId);

        List<Map<String, Object>> list = new ArrayList<>();
        for (long emId : sortMap.keySet()) {
            EquipmentInfo ei = eiMap.get(emId);
            Map<String, Object> map = new HashMap<>();
            map.put("emName", ei.getEmName());
            map.put("treeName", etMap.get(ei.getEmTree()).getName());
            map.put("count", sortMap.get(emId));
            list.add(map);
        }

        return DataResult.build9100(list);
    }

    @Override
    public DataResult selectPatrol(LoginInfo loginInfo, CountDto countDto) throws Exception {
        HomeLocalDateDto dateDto = commonService.selectCountTime(countDto);

        PatrolWorkOrderExample pwoExample = new PatrolWorkOrderExample();
        PatrolWorkOrderExample.Criteria pwoCriteria = pwoExample.createCriteria();
        pwoCriteria.andCreateTimeBetween(dateDto.getStartTime(), dateDto.getEndTime());
        List<PatrolWorkOrder> pwoList = patrolWorkOrderMapper.selectByExample(pwoExample);

        Map<String, List<Integer>> pwoMap = new HashMap<>();
        for (PatrolWorkOrder pwo : pwoList) {
            String key = DateUtil.formatDate(pwo.getCreateTime());
            List<Integer> pwoMapList;
            if (pwoMap.containsKey(key)) {
                pwoMapList = pwoMap.get(key);
            } else {
                pwoMapList = CollUtil.newArrayList(0, 0);
            }
            pwoMapList.set(0, pwoMapList.get(0) + 1);
            if (pwo.getIsException() == 1) {
                pwoMapList.set(1, pwoMapList.get(1) + 1);
            }
            pwoMap.put(key, pwoMapList);
        }

        List<DateTime> dateList = DateUtil.rangeToList(dateDto.getStartTime(), dateDto.getEndTime(), DateField.DAY_OF_YEAR);

        List<String> chartNameList = new ArrayList<>();
        Map<String, Object> allMap = new HashMap<>();
        Map<String, Object> exceptionMap = new HashMap<>();

        List<Integer> allDataList = new ArrayList<>();
        List<Integer> exceptionDataList = new ArrayList<>();
        for (DateTime day : dateList) {
            chartNameList.add(DateUtil.format(day, "MM-dd"));
            String key = DateUtil.formatDate(day);
            if (pwoMap.containsKey(key)) {
                List<Integer> pwoMapList = pwoMap.get(key);
                allDataList.add(pwoMapList.get(0));
                exceptionDataList.add(pwoMapList.get(1));
            } else {
                allDataList.add(0);
                exceptionDataList.add(0);
            }
        }

        List<Map<String, Object>> chartRowsList = new ArrayList<>();
        allMap.put("name", "巡检总单数");
        allMap.put("type", "line");
        allMap.put("data", allDataList);
        chartRowsList.add(allMap);

        exceptionMap.put("name", "巡检异常单数");
        exceptionMap.put("type", "line");
        exceptionMap.put("data", exceptionDataList);
        chartRowsList.add(exceptionMap);

        Map<String, Object> map = new HashMap<>();
        map.put("chartName", chartNameList);
        map.put("chartRows", chartRowsList);
        return DataResult.build9100(map);
    }

    @Override
    public DataResult selectHour(LoginInfo loginInfo, CountDto countDto) throws Exception {
        HomeLocalDateDto dateDto = commonService.selectCountTime(countDto);

        RepairWorkOrderExample rwoExample = new RepairWorkOrderExample();
        RepairWorkOrderExample.Criteria rwoCriteria = rwoExample.createCriteria();
        rwoCriteria.andCreateTimeBetween(dateDto.getStartTime(), dateDto.getEndTime());
        List<RepairWorkOrder> rwoList = repairWorkOrderMapper.selectByExample(rwoExample);
        Map<String, Integer> rwoMap = new HashMap<>();
        for (RepairWorkOrder rwo : rwoList) {
            if (rwo.getWorkHourSecond() == null || rwo.getWorkHourSecond() == 0) {
                continue;
            }
            String key = DateUtil.formatDate(rwo.getCreateTime());
            int rwoMapSecond = (int) (rwoMap.getOrDefault(key, 0) + rwo.getWorkHourSecond());
            rwoMap.put(key, rwoMapSecond);
        }

        UpkeepWorkOrderExample uwoExample = new UpkeepWorkOrderExample();
        UpkeepWorkOrderExample.Criteria uwoCriteria = uwoExample.createCriteria();
        uwoCriteria.andCreateTimeBetween(dateDto.getStartTime(), dateDto.getEndTime());
        List<UpkeepWorkOrder> uwoList = upkeepWorkOrderMapper.selectByExample(uwoExample);
        Map<String, Integer> uwoMap = new HashMap<>();
        for (UpkeepWorkOrder uwo : uwoList) {
            if (uwo.getWorkHourSecond() == null || uwo.getWorkHourSecond() == 0) {
                continue;
            }
            String key = DateUtil.formatDate(uwo.getCreateTime());
            int uwoMapSecond = (int) (uwoMap.getOrDefault(key, 0) + uwo.getWorkHourSecond());
            uwoMap.put(key, uwoMapSecond);
        }

        PatrolWorkOrderExample pwoExample = new PatrolWorkOrderExample();
        PatrolWorkOrderExample.Criteria pwoCriteria = pwoExample.createCriteria();
        pwoCriteria.andCreateTimeBetween(dateDto.getStartTime(), dateDto.getEndTime());
        List<PatrolWorkOrder> pwoList = patrolWorkOrderMapper.selectByExample(pwoExample);
        Map<String, Integer> pwoMap = new HashMap<>();
        for (PatrolWorkOrder pwo : pwoList) {
            if (pwo.getOrderWorkHour() == null || pwo.getOrderWorkHour() == 0) {
                continue;
            }
            String key = DateUtil.formatDate(pwo.getCreateTime());
            int pwoMapSecond = pwoMap.getOrDefault(key, 0) + pwo.getOrderWorkHour() * 60;
            pwoMap.put(key, pwoMapSecond);
        }

        List<DateTime> dateList = DateUtil.rangeToList(dateDto.getStartTime(), dateDto.getEndTime(), DateField.DAY_OF_YEAR);

        List<String> chartNameList = new ArrayList<>();

        List<BigDecimal> repairDataList = new ArrayList<>();
        List<BigDecimal> upkeepDataList = new ArrayList<>();
        List<BigDecimal> patrolDataList = new ArrayList<>();
        List<BigDecimal> allDataList = new ArrayList<>();
        for (DateTime day : dateList) {
            chartNameList.add(DateUtil.format(day, "MM-dd"));
            String key = DateUtil.formatDate(day);
            BigDecimal repairSecond = BigDecimal.valueOf(rwoMap.getOrDefault(key, 0));
            BigDecimal upkeepSecond = BigDecimal.valueOf(uwoMap.getOrDefault(key, 0));
            BigDecimal patrolSecond = BigDecimal.valueOf(pwoMap.getOrDefault(key, 0));

            BigDecimal repairHour = NumberUtil.div(repairSecond, BigDecimal.valueOf(3600), 2, RoundingMode.HALF_UP);
            BigDecimal upkeepHour = NumberUtil.div(upkeepSecond, BigDecimal.valueOf(3600), 2, RoundingMode.HALF_UP);
            BigDecimal patrolHour = NumberUtil.div(patrolSecond, BigDecimal.valueOf(3600), 2, RoundingMode.HALF_UP);
            repairDataList.add(repairHour);
            upkeepDataList.add(upkeepHour);
            patrolDataList.add(patrolHour);
            allDataList.add(NumberUtil.add(repairHour, upkeepHour, patrolHour));
        }

        List<Map<String, Object>> chartRowsList = new ArrayList<>();

        Map<String, String> focusMap = new HashMap<>();
        focusMap.put("focus", "series");

        Map<String, Object> repairMap = new HashMap<>();
        repairMap.put("name", "维修工时");
        repairMap.put("type", "bar");
        repairMap.put("stack", "Times");
        repairMap.put("emphasis", focusMap);
        repairMap.put("data", repairDataList);
        chartRowsList.add(repairMap);

        Map<String, Object> upkeepMap = new HashMap<>();
        upkeepMap.put("name", "维保工时");
        upkeepMap.put("type", "bar");
        upkeepMap.put("stack", "Times");
        upkeepMap.put("emphasis", focusMap);
        upkeepMap.put("data", upkeepDataList);
        chartRowsList.add(upkeepMap);

        Map<String, Object> patrolMap = new HashMap<>();
        patrolMap.put("name", "巡检工时");
        patrolMap.put("type", "bar");
        patrolMap.put("stack", "Times");
        patrolMap.put("emphasis", focusMap);
        patrolMap.put("data", patrolDataList);
        chartRowsList.add(patrolMap);

        Map<String, Object> allMap = new HashMap<>();
        allMap.put("name", "总工时");
        allMap.put("type", "line");
        allMap.put("stack", "");
        allMap.put("data", allDataList);

        Map<String, Object> map = new HashMap<>();
        map.put("chartName", chartNameList);
        map.put("chartRows", chartRowsList);
        map.put("allRows", allMap);
        return DataResult.build9100(map);
    }
}
